//
// Biblioteca com classes uteis para modelagem. 
//
// DataReader -> fornecer interface util para leitura de arquivos de dados complexos e facil eteracao
// com os mesmos.
//

#include "dataFileReader_v0.1.1/dataFileReader.h"

class DataReader {
  
  //Algumas definicoes do arquivo de entrada
  // Input File Definition - IFD:  
  //     Number of fixed Parameters lines      -  IFD_NP
  //     Number of columns Parameters          - *IFD_P (array[IFD_NP])
  //     Spot Line(onde com. def. de spot - 1) -  IFD_SL
  //     Number of Spot Parameters             -  IFD_SP
  //     posicao da lei de obs. de Borda       -  IFD_B
  
  int __IFDNP;        //= 2;
  int *__IFDP; //= {5, 7};
  int __IFDSL;        //= 3;
  int __IFDSP;        //= 5;
  int *__IFDB_2;         //= 2;
  int *__IFDB_1;
	double _f0;
  double _f1;
  double _df;
  vector<vector<double> > _par;
  vector<vector<string> > _pardef;
  vector<double> phases;
  public:
    DataReader(int argc, char** argv){
      if(argc < 3){
	cout << " Modo de utilizacao do programa:\n"
	    << "cl_new_v.X.X arq_in arq_out [fase.dat]\n" 
	    << "onde arq_in o arquivo com os parametros de entrada e arq_out o\n" 
	    << "arquivo para serem escritos os resultados. Opcionalmente pode\n"
	    << "se incluir um arquivo com as fases desejadas para serem\n"
	    << "calculados os fluxos ([fase.dat]).\n\n"
	    << "Formato do arquivo de entrada:\n"
	    << "1a. linha de dados:\n"
	    << "  nslices - Numero de cortes para o algoritimo de pixelizacao (<5)\n"
	    << "2a. linha de dados (sem contar linha de comentario):\n"
	    << "  i  - inclinacao (graus).\n"
	    << "  M1 - Massa da Primaria.\n"
	    << "  M2 - Massa da Secundaria. (q = M2/M1)\n"
	    << "  P  - Periodo Orbital (hrs).\n"
	    << "  S/N- Relacao Sinal-Ruido na curva\n"
	    << "3a. linha de dados:\n"
	    << "  f2        - fluxo da secundaria em fase 0.\n"
	    << "  grav_coef2 - coeficiente do obscurecimento gravitacional.\n"
	    << "  limb_law2  - lei de obscurecimento de borda.\n"
	    << "  nspot2     - Numero de spots.\n"
	    << "  Tpole2     - Temperatura do polo da estrela.\n"
	    << "  f_fac2     - Fator multiplicativo ao potencial do lobo de\n"
	    << "              Roche, que define a superficie da estrela secundaria.\n"
	    << "  A2         - Coeficiente bolométrico de albedo.\n"
	    << "  Irr2       - Intensidade irradiante.\n" 
		<< "4a. linha de dados:\n"
		<< "  f1        - fluxo da primaria em fase 0.5.\n"
		<< "  grav_coef1 - coeficiente do obscurecimento gravitacional.\n"
		<< "  limb_law1  - lei de obscurecimento de borda.\n"
		<< "  nspot1     - Numero de spots.\n"
		<< "  Tpole1     - Temperatura do polo da estrela.\n"
		<< "  f_fac1     - Fator multiplicativo ao potencial do lobo de\n"
		<< "               Roche, que define a superficie da estrela Primaria.\n"
		<< "  A1         - Coeficiente bolométrico de albedo.\n"
		<< "  Irr       - Intensidade irradiante.\n" 
	    << "5a. linha de dados:\n"
	    << "  (coeficientes de obscurecimento de borda da secundaria)\n"
		<< "6a. linha de dados:\n"
		<< "  (coeficientes de obscurecimento de borda da primaria)\n"
		<< "7a. a (7a+nspot2) linhas de dados:\n"
	    << "  theta - posicao theta do spot_2\n"
	    << "  phi   - posicao phi do spot_2\n"
	    << "  dt    - largura a meia altura em theta\n"
	    << "  dp    - largura a meia altura em phi\n"
	    << "  Is    - Intensidade em relacao a I_L1\n\n"
		<< "7a+nspot2 a (7a+nspot2+nspot1) linhas de dados:\n"
		<< "  theta - posicao theta do spot_1\n"
		<< "  phi   - posicao phi do spot_1\n"
		<< "  dt    - largura a meia altura em theta\n"
		<< "  dp    - largura a meia altura em phi\n"
		<< "  Is    - Intensidade em relacao a I_L1\n\n"
		//<< "Albedo possui parametros default px = 1, py = pz = 0 (wd position).\n"
	    << "Tiago Ribeiro - LinuxC++ - 2006\n";
	exit(1);
      }
       // Input File Definition - IFD:  
  //     Number of fixed Parameters lines      -  IFD_NP
  //     Number of columns Parameters          - *IFD_P (array[IFD_NP])
  //     Spot Line(onde com. def. de spot - 1) -  IFD_SL
  //     Number of Spot Parameters             -  IFD_SP
  //     posicao da lei de obs. de Borda       -  IFD_B

      __IFDNP = 6;
      __IFDP = new int [__IFDNP];
      __IFDP[0] = 1;
	  __IFDP[1] =5;
      __IFDP[2] =8;
      __IFDP[3] =8;
      __IFDP[4] =0;
      __IFDP[5] =0;
	  __IFDSL = 6;
	  __IFDSP = 5;
	  __IFDB_1 = new int [3];
	  __IFDB_2 = new int [3];
      __IFDB_1[0] = 5;
      __IFDB_1[1] = 2;
      __IFDB_1[2] = 2;
	  __IFDB_2[0] = 4;
	  __IFDB_2[1] = 3;
	  __IFDB_2[2] = 2;
	  _f0=-0.5;
      _f1=0.5;
      _df=0.01;

      //Leio parametros
      DataFileReader read(argv[1]);
      _par.resize(__IFDNP);
      for(int i = 0; i < __IFDNP; i++){
		  if(i==__IFDB_2[0]) __IFDP[4]=definicoes_obscurecimento(int(_par[__IFDB_2[1]][__IFDB_2[2]]));
		  
		  if(i==__IFDB_1[0]) __IFDP[5]=definicoes_obscurecimento(int(_par[__IFDB_1[1]][__IFDB_1[2]]));
		  
		  _par[i].resize(__IFDP[i]);
		  ++read;

		  for(int j = 0; j < __IFDP[i]; j++){
			  _par[i][j] = read.readColumn<double>(j+1);

		  }
			  
	  }
      for(int i = __IFDNP; i < __IFDNP+nspot(); i++){
	_par.push_back(_par[0]);
	_par[i].resize(__IFDSP);
	++read;
	for(int j = 0; j < __IFDSP; j++)
	  _par[i][j] = read.readColumn<double>(j+1);
      }
      read.close();
//      cout<<"# - Parameters reading [DONE]\n";
      if(argc > 3){
	DataFileReader ffases(argv[3]);
	while(!++ffases)
	  phases.push_back(ffases.readColumn<double>(1));
      }
      else for (double ff = _f0; ff <= _f1+_df; ff+=_df) phases.push_back(ff);
      
      //Parameters definitions
      _pardef.resize(_par.size());
      _pardef[0].push_back("nslices = ");
      
      _pardef[1].push_back("i = ");
      _pardef[1].push_back("M1 = ");
      _pardef[1].push_back("M2 = ");
      _pardef[1].push_back("P = ");
      _pardef[1].push_back("S/N = ");
      
      _pardef[2].push_back("f2 = ");
      _pardef[2].push_back("grav_coef2 = ");
      _pardef[2].push_back("limb_law2 = ");
      _pardef[2].push_back("nspot2 = ");
      _pardef[2].push_back("Tpole2 = ");
      _pardef[2].push_back("f_fac2 = ");
      _pardef[2].push_back("A2 = ");
      _pardef[2].push_back("Irr2 = ");
		
	  _pardef[3].push_back("f1 = ");
	  _pardef[3].push_back("grav_coef1 = ");
	  _pardef[3].push_back("limb_law1 = ");
	  _pardef[3].push_back("nspot1 = ");
	  _pardef[3].push_back("Tpole1 = ");
	  _pardef[3].push_back("f_fac1 = ");
	  _pardef[3].push_back("A1 = ");
	  _pardef[3].push_back("Irr1 = ");
      
      for(int i = 0; i < _par[4].size(); i++){
	ostringstream str0;
	str0 << "x" << i << " = ";
	_pardef[4].push_back(str0.str());
      }

		for(int i = 0; i < _par[5].size(); i++){
			ostringstream str0;
			str0 << "x" << i << " = ";
			_pardef[5].push_back(str0.str());
		}
		
		
      if(nspot() > 0){
	_pardef[6].push_back("theta = ");
	_pardef[6].push_back("phi = ");
	_pardef[6].push_back("dt = ");
	_pardef[6].push_back("dp = ");
	_pardef[6].push_back("Is = ");
      }
      
//      cout << "# - Reading is done...\n";
    };
    
    int inline slaces(void){return int(_par[0][0]);};
    int inline definicoes_obscurecimento(const int law)
    {
      vector<vector<double> > par;

      Light_Curve teste(par);
  
      return teste.npar_obs_borda(law);
    };
    
    vector<vector<double> > inline org_par(int component = 0)
    {
      vector<vector<double> > saida;
      if (component != 0 && component != 1) aborta("Component is either 0 or 1 ...")
		// saida[0] = par[1]
	  saida.push_back(_par[1]);
	  if (component == 1){// P/ component = 1 trocar M1 com M2
		  saida[0][1] = _par[1][2];
		  saida[0][2] = _par[1][1];
	  } 
	  //saida[1] = par[2] (se component = 0) ou = par[3] (se component = 1)
		saida.push_back(_par[2+component]);

	  //saida[2] = par[4] (se component = 0) ou = par[5] (se component = 1)

		saida.push_back(_par[4+component]);
	  //saida[3] ate saida[3+saida[1][3]] = par[6] ate par[6+par[2][3]] se component = 0
	  // ou = par[6+par[2][3]] ate par[6+par[2][3]+par[3][3]] se component = 1
	  if (component == 0){
		  for (int i = 0; i < _par[2][3]; i++) {
			  saida.push_back(_par[6+i]);
		  }
	  }
	  if (component == 1) {
		  for (int i = _par[2][3]; i < _par[3][3] ; i++) {
			  saida.push_back(_par[6+i]);
		  }
	  }
		
      saida[0][0]*=M_PI/180.0;
      return saida;
    }
    int nspot(int component = 0){return int(_par[2+component][3]);};
	//int nspot_2(void){return int(_par[3][3]);};
    double Iwd(void){return _par[3][0];};
    double Irr(int component = 0){return _par[2+component][7];};
    double Albedo(int component = 0){return _par[2+component][6];};
    double nfases(void){return phases.size();};
    double ff(int nf){return phases[nf];};
    double f0(void){return _f0;};
    double f1(void){return _f1;};
    double df(void){return _df;};
    void f0(double val){_f0=val;};
    void f1(double val){_f1=val;};
    void df(double val){_df=val;};

    double fot_erro(void)
    {
      if(_par[1][4] > 0.0) return 1.0/_par[1][4];
      else return 0.0;
    };
	
    void inline show_par(ostream& out)
    {
      for( int i = 0; i < _par.size(); i++){
	out<<"# ";
	for(int ii = 0; ii < _par[i].size(); ii++){
	  if(i < 6) out << _pardef[i][ii] << _par[i][ii] << " | ";
	  else out << _pardef[6][ii] << _par[i][ii] << " | ";
	}
	out<<endl;
      }
    };
};

